package com.mcxx.modules.miniSalvation.fundpay.service.read;

import com.google.common.collect.Lists;
import com.mcxx.common.exception.BizException;
import com.mcxx.modules.base.utils.QueryParamUtil;
import com.mcxx.modules.miniSalvation.family.entity.BankEntity;
import com.mcxx.modules.miniSalvation.fundpay.dao.read.FundPayFamilyReadDao;
import com.mcxx.modules.miniSalvation.fundpay.dao.read.FundPayMemberReadDao;
import com.mcxx.modules.miniSalvation.fundpay.dto.*;
import com.mcxx.modules.miniSalvation.fundpay.entity.FundPayEntity;
import com.mcxx.modules.miniSalvation.fundpay.entity.FundPayFamilyEntity;
import com.mcxx.modules.miniSalvation.fundpay.entity.FundPayMemberEntity;
import com.mcxx.modules.miniSalvation.fundpay.param.CustomFundPayMemberParam;
import com.mcxx.modules.miniSalvation.fundpay.param.FundPayFamilyParam;
import com.mcxx.modules.statistics.entity.MemberInfoEntity;
import com.mcxx.util.CommonUtil;
import com.mcxx.util.Constant;
import com.mcxx.util.DateUtil;
import com.mcxx.util.FailureCode;
import com.yinhai.ta404.core.restservice.requestbean.PageParam;
import com.yinhai.ta404.core.restservice.resultbean.Page;
import com.yinhai.ta404.core.security.vo.UserAccountVo;
import com.yinhai.ta404.core.service.BaseService;
import com.yinhai.ta404.core.transaction.annotation.TaTransactional;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;


@Service
@TaTransactional(readOnly = true)
public class FundPayFamilyReadService extends BaseService {

    @Autowired
    private FundPayFamilyReadDao fundPayFamilyReadDao;

    @Autowired
    private FundPayMemberReadDao fundPayMemberReadDao;



    public List<FundPayFamilyDTO> getDTOByFundPayId(String fundPayId){
        return fundPayFamilyReadDao.getDTOByFundPayId(fundPayId);
    }


    public int cntFundNumberZero(String fundPayId){
        return fundPayFamilyReadDao.cntFundNumberZero(fundPayId);
    }




    public List<FundPayFamilyEntity> getFamilyByCreateCapital(CapitalFundPayDTO capitalFundPayDTO){
        return fundPayFamilyReadDao.getFamilyByCreateCapital(capitalFundPayDTO);
    }


    public void cntFamilyByCapital(CapitalFundPayDTO capitalFundPayDTO, UserAccountVo userAccountVo){

        FundPayDTO fundPayDTO = new FundPayDTO();
        BeanUtils.copyProperties(capitalFundPayDTO, fundPayDTO);
        QueryParamUtil.setBaseParamValue(fundPayDTO, userAccountVo);

        List<String> rst = fundPayFamilyReadDao.cntFamilyByCapitalAndAllowance(fundPayDTO);
        if(rst.size() <= 0){

            throw new BizException("-1", "名册为空，无法生成");
        }
    }


    public List<String> cntFamilyByCapitalList(CapitalFundPayDTO capitalFundPayDTO, UserAccountVo userAccountVo){

        FundPayDTO fundPayDTO = new FundPayDTO();
        BeanUtils.copyProperties(capitalFundPayDTO, fundPayDTO);
        QueryParamUtil.setBaseParamValue(fundPayDTO, userAccountVo);

        List<String> rst = fundPayFamilyReadDao.cntFamilyByCapitalAndAllowanceList(fundPayDTO);
        if(rst.size() <= 0){

            throw new BizException("-1", "名册为空，无法生成");
        }
        return rst;
    }


    public int verifyNoCompleteNotice(String fundPayId){
        return fundPayFamilyReadDao.getIdcardNoCompleteNotice(fundPayId);
    }


    public Page getNoSaveCapitalFamilyList(CapitalFundPayDTO capitalFundPayDTO, PageParam pageParam){
        fundPayFamilyReadDao.beginPager(pageParam);
        List<FundPayFamilyDTO> list = fundPayFamilyReadDao.getNoSaveCapitalFamilyList(capitalFundPayDTO);
        return fundPayFamilyReadDao.endPager(list);
    }


    public Page getFundPayFamilyList(FundPayFamilyParam fundPayFamilyParam, PageParam pageParam, UserAccountVo userAccountVo){
        QueryParamUtil.setBaseParamValue(fundPayFamilyParam, userAccountVo);
        fundPayFamilyReadDao.beginPager(pageParam);
        List<FundPayFamilyDTO> list = fundPayFamilyReadDao.getFundPayFamilyList(fundPayFamilyParam);
        return fundPayFamilyReadDao.endPager(list);
    }



    public List<FundPayFamilyExcelDTO>  exportFundPayFamilyList(FundPayFamilyParam fundPayFamilyParam){
        return fundPayFamilyReadDao.getFundPayFamilyExcelList(fundPayFamilyParam);
    }


    public List<FundPayFamilyEntity> getSaveCapitalFamilyByOrderId(List<String> orderIdList, String costType, String businessType){
        return fundPayFamilyReadDao.getSaveCapitalFamilyByOrderId(orderIdList, costType,businessType);
    }








    public List<String> cntFamilyByStand(StandFundPayDTO standFundPayDTO, UserAccountVo userAccountVo){

        StandFundPayDTO standFundPayDTONew = new StandFundPayDTO();
        BeanUtils.copyProperties(standFundPayDTO, standFundPayDTONew);

        standFundPayDTONew.setSalaryType(
                Constant.StandFundPayReplacementType.WELFARE.equals(standFundPayDTO.getReplacementType())
                ? Constant.SalaryType.WELFARE_REISSUE
                : Constant.SalaryType.SUSPEND_REISSUE);

        QueryParamUtil.setBaseParamValue(standFundPayDTONew, userAccountVo);


        List<String> rst = fundPayFamilyReadDao.cntFamilyByStand(standFundPayDTONew);
        if(rst.size() <= 0){

            throw new BizException("-1", "名册为空，无法生成");
        }

        if (Constant.SupplyType.SUPPLY_DISPERSE.equals(standFundPayDTO.getSupplyType())) {
            List<FundPayMemberEntity> carePersonInfo = fundPayMemberReadDao.getCarePersonInfo(rst, standFundPayDTO.getCareType(), standFundPayDTO.getPayDate());
            if(carePersonInfo.size() <= 0){
                throw new BizException("-1", "没有可以添加到名册的对象，无法生成");
            }
        }
        return  rst;
    }


    public List<FundPayFamilyEntity> getFamilyByCreateStand(StandFundPayDTO standFundPayDTO){
        return fundPayFamilyReadDao.getFamilyByCreateStand(standFundPayDTO);
    }


    public Page getNoSaveStandFamilyList(StandFundPayDTO standFundPayDTO, PageParam pageParam){
        fundPayFamilyReadDao.beginPager(pageParam);
        List<FundPayFamilyDTO> list = null;
        if (Constant.SupplyType.SUPPLY_DISPERSE.equals(standFundPayDTO.getSupplyType())) {
            list = fundPayFamilyReadDao.getNoSaveStandDisperseFamilyList(standFundPayDTO);
        } else {
            list = fundPayFamilyReadDao.getNoSaveStandFamilyList(standFundPayDTO);
        }
        return fundPayFamilyReadDao.endPager(list);
    }



    public List<FundPayFamilyEntity> getSaveStandFamilyByOrderId(List<String> orderIdList, String costType, String bussinessType){
        return fundPayFamilyReadDao.getSaveStandFamilyByOrderId(orderIdList, costType, bussinessType);
    }








    public List<FundPayFamilyEntity> getFamilyByCreateAllowance(AllowanceFundPayDTO allowanceFundPayDTO){
        return fundPayFamilyReadDao.getFamilyByCreateAllowance(allowanceFundPayDTO);
    }


    public List<String> cntFamilyByAllowance(AllowanceFundPayDTO allowanceFundPayDTO, UserAccountVo userAccountVo){

        FundPayDTO fundPayDTO = new FundPayDTO();
        BeanUtils.copyProperties(allowanceFundPayDTO, fundPayDTO);
        QueryParamUtil.setBaseParamValue(fundPayDTO, userAccountVo);

        List<String> rst = fundPayFamilyReadDao.cntFamilyByCapitalAndAllowance(fundPayDTO);
        if(rst.size() <= 0){

            throw new BizException("-1", "名册为空，无法生成");
        }
        return rst;
    }


    public List<FundPayFamilyEntity> getFamilyByAddAllowanceMember(String fundPayId,
                                                            List<String> orderIdList,
                                                            List<String> familyIdList,
                                                            String businessType){
        return fundPayFamilyReadDao.getFamilyByAddAllowanceMember(fundPayId, orderIdList, familyIdList, businessType);
    }








    public Page getNoSaveCustomFamilyList(CustomFundPayDTO customFundPayDTO, PageParam pageParam, UserAccountVo userAccountVo){

        QueryParamUtil.setBaseParamValue(customFundPayDTO, userAccountVo);
        fundPayFamilyReadDao.beginPager(pageParam);
        List<FundPayFamilyDTO> list = fundPayFamilyReadDao.getNoSaveCustomFamilyList(customFundPayDTO);
        return fundPayFamilyReadDao.endPager(list);
    }


    public List<FundPayFamilyEntity> getSaveCustomFamilyByOrderId(List<String> orderIdList, String businessType){
        return  fundPayFamilyReadDao.getSaveCustomFamilyByOrderId(orderIdList, businessType);
    }


    public List<FundPayFamilyEntity> getFamilyByAddCustomMember(String fundPayId,
                                                                List<String> orderIdList,
                                                                List<String> familyIdList,
                                                                String businessType){
        return fundPayFamilyReadDao.getFamilyByAddCustomMember(fundPayId, orderIdList, familyIdList, businessType);
    }








    public List<String> getFamilyId(String fundPayId){
        return fundPayFamilyReadDao.getFamilyId(fundPayId);
    }


    public FundPayEntity getCustomRollById(String customFundPayId) {
        FundPayEntity customFundPayDTO = fundPayFamilyReadDao.getCustomRollById(customFundPayId);
        if(null == customFundPayDTO){
            throw new BizException(FailureCode.ERR_10042);
        }
        return customFundPayDTO;
    }

    public List<FundPayMemberEntity> getCustomMemberListByIdcard(FundPayEntity customFundPayDTO, List<String> idcardList, UserAccountVo curUserAccount) {

        CustomFundPayMemberParam customFundPayMemberParam = new CustomFundPayMemberParam();

        customFundPayMemberParam.setAreaCode(CommonUtil.invalidArgs(customFundPayMemberParam.getAreaCode()) ? customFundPayDTO.getAreaCode() : customFundPayMemberParam.getAreaCode());
        QueryParamUtil.setBaseParamValue(customFundPayMemberParam, curUserAccount);
        customFundPayMemberParam.setStandType(customFundPayDTO.getStandType());
        String date = DateUtil.formatDate(customFundPayDTO.getPayDate(),"yyyy-MM-dd");
        customFundPayMemberParam.setPayDate(date);
        customFundPayMemberParam.setSupplyType(customFundPayDTO.getSupplyType());

        if (Constant.BusinessCode.TEKUN.equals(customFundPayDTO.getBusinessType())
                && Constant.CapitalFundPayCostType.NURSING.equals(customFundPayDTO.getCostType())
        ) {
            if (Constant.SupplyType.SUPPLY_DISPERSE.equals(customFundPayDTO.getSupplyType())) {
                customFundPayDTO.setAreaCode(customFundPayMemberParam.getAreaCode());
                return fundPayFamilyReadDao.getCustomMemberListByIdCardAndCarePerson(customFundPayDTO, idcardList);
            } else {
                return fundPayFamilyReadDao.getCustomMemberListByIdCardForFocus(customFundPayMemberParam, idcardList);
            }
        } else {
            return fundPayFamilyReadDao.getCustomMemberListByIdcard(customFundPayMemberParam, idcardList);
        }
    }



    public List<String> getDoingOrderBySourceIds(List<String> ids) {
        return fundPayFamilyReadDao.selectDoingOrderBySourceIds(ids);
    }


    public List<FundPayFamilyEntity> getNurseFamilyByCreateCapital(CapitalFundPayDTO capitalFundPayDTO) {
        return fundPayFamilyReadDao.getNurseFamilyByCreateCapital(capitalFundPayDTO);
    }


    public List<String> getHistoryNoDeadMember(List<String> idCards) {
        return fundPayFamilyReadDao.getHistoryNoDeadMember(idCards);
    }

    public List<String> getHistoryNoDeadFamily(List<String> idCards) {
        return fundPayFamilyReadDao.getHistoryNoDeadFamily(idCards);
    }


    public List<String> getOrderIdsByFundPayId(String fundPayId) {
        return fundPayFamilyReadDao.getOrderIdsByFundPayId(fundPayId);
    }


    public List<String> cntCareOrderByCapital(CapitalFundPayDTO capitalFundPayDTO, UserAccountVo userAccountVo) {
        List<FundPayFamilyEntity> rst = new ArrayList<>();
        FundPayDTO fundPayDTO = new FundPayDTO();
        BeanUtils.copyProperties(capitalFundPayDTO, fundPayDTO);
        QueryParamUtil.setBaseParamValue(fundPayDTO, userAccountVo);

        List<FundPayFamilyEntity> save = fundPayFamilyReadDao.cntCareOrderByCapital(fundPayDTO);

        List<String> orderIdList = save.stream().map(FundPayFamilyEntity::getOrderId).collect(Collectors.toList());
        if (orderIdList.isEmpty()) {
            throw new BizException("-1", "名册为空，无法生成");
        }
        List<FundPayMemberEntity> suspends = fundPayMemberReadDao.getCareFeeSuspendPersonInfo(orderIdList);
        dealWithSuspendMember(rst, save, suspends);
        if(rst.size() <= 0){

            throw new BizException("-1", "名册为空，无法生成");
        }
        return orderIdList;
    }

    public Page getFocusCapitalObjectList(FundPayFamilyParam fundPayFamilyParam, PageParam pageParam, UserAccountVo userAccountVo) {
        QueryParamUtil.setBaseParamValue(fundPayFamilyParam, userAccountVo);
        fundPayFamilyReadDao.beginPager(pageParam);
        List<FundPayMemberDTO> list = fundPayFamilyReadDao.getFocusCapitalObjectList(fundPayFamilyParam);
        this.dealBankInfo(list, fundPayFamilyParam);
        return fundPayFamilyReadDao.endPager(list);
    }


    private void dealBankInfo(List<FundPayMemberDTO> fundPayFamilyList, FundPayFamilyParam params) {
        CapitalFundPayDTO capitalFundPayDTO = new CapitalFundPayDTO();
        BeanUtils.copyProperties(params,capitalFundPayDTO);
        List<String> familyIds = fundPayFamilyList.stream().map(FundPayMemberDTO::getFamilyId).collect(Collectors.toList());
        List<String> memberIds = fundPayFamilyList.stream().map(FundPayMemberDTO::getMemberId).collect(Collectors.toList());
        List<BankEntity> bankInfos = this.getBankInfoForFamily(capitalFundPayDTO, familyIds, memberIds);

        for (FundPayMemberDTO obj : fundPayFamilyList) {
            for (BankEntity bank : bankInfos) {
                if (obj.getFamilyId().equals(bank.getFamilyId()) && obj.getMemberId().equals(bank.getMemberId())) {
                    obj.setBankName(bank.getBankName());
                    obj.setAccount(bank.getMasterAccount());
                    obj.setSubsideProps(bank.getMasterSubsideProps());
                }
            }
        }
    }

    public List<FundPayMemberDTO> getFocusCapitalObjectListExcel(FundPayFamilyParam fundPayFamilyParam) {
        return fundPayFamilyReadDao.getFocusCapitalObjectList(fundPayFamilyParam);
    }


    public List<FundPayFamilyEntity> getFocusNurseFamilyByCreateCapital(CapitalFundPayDTO capitalFundPayDTO) {
        return fundPayFamilyReadDao.getFocusNurseFamilyByCreateCapital(capitalFundPayDTO);
    }


    private void dealWithSuspendMember(List<FundPayFamilyEntity> fundPayFamilyList, List<FundPayFamilyEntity> saveFamilyList, List<FundPayMemberEntity> suspends) {
        Map<String, List<FundPayFamilyEntity>> savingFamily = saveFamilyList.stream().collect(Collectors.groupingBy(FundPayFamilyEntity::getFamilyId));
        Map<String, List<FundPayMemberEntity>> suspendFamily = suspends.stream().collect(Collectors.groupingBy(FundPayMemberEntity::getFamilyId));
        Set<String> keySet = suspendFamily.keySet();
        Set<String> keySetFamily = savingFamily.keySet();
        List<FundPayFamilyEntity> tempFamilyList = new ArrayList<>();
        for (String key: keySet) {
            List<FundPayMemberEntity> suspend = suspendFamily.get(key);
            List<FundPayFamilyEntity> save = savingFamily.get(key);
            FundPayFamilyEntity tempFamily = save.get(0);
            if (suspend.size() == tempFamily.getPersonNumber()) {
                continue;
            }
            if (suspend.size() < tempFamily.getPersonNumber()) {
                tempFamily.setPersonNumber(tempFamily.getPersonNumber() - suspend.size());
                Double fundNumber = suspend.stream().mapToDouble(FundPayMemberEntity::getFundNumber).sum();
                tempFamily.setFundNumber(tempFamily.getFundNumber() - fundNumber);
                tempFamilyList.add(tempFamily);
            }
        }

        List<String> diffKey = keySetFamily.stream().filter(item -> !keySet.contains(item)).collect(Collectors.toList());
        for (String key : diffKey) {
            tempFamilyList.addAll(savingFamily.get(key));
        }
        if (!tempFamilyList.isEmpty())
            fundPayFamilyList.addAll(tempFamilyList);
    }


    public List<BankEntity> getBankInfoForFamily(CapitalFundPayDTO obj, List<String> familyIds, List<String> memberIds) {
        List<BankEntity> lastBanks = new ArrayList<>();
        List<List<String>> groupFamilyIds = Lists.partition(familyIds, 512);
        List<List<String>> groupMemberIds = Lists.partition(memberIds, 512);

        for (int i = 0; i < groupFamilyIds.size(); i++) {
            List<BankEntity> subList = fundPayFamilyReadDao.getBankInfoForFamily(obj.getBusinessType(), obj.getAreaCode(), groupFamilyIds.get(i), groupMemberIds.get(i));
            lastBanks.addAll(subList);
        }
        return lastBanks;
    }


    public List<FundPayMemberEntity> getHistoryDeadAndStopInfo(List<String> orderIds) {
        return fundPayFamilyReadDao.getHistoryDeadAndStopInfo(orderIds);
    }


    public List<FundPayFamilyEntity> getFamilyForDisperseStandRoll(StandFundPayDTO standFundPayDTO) {
        return fundPayFamilyReadDao.getFamilyForDisperseStandRoll(standFundPayDTO);
    }

    public List<FundPayFamilyEntity> getFamilyForFocusStandRoll(StandFundPayDTO standFundPayDTO) {
        return fundPayFamilyReadDao.getFamilyForFocusStandRoll(standFundPayDTO);
    }


    public List<MemberInfoEntity> selectDeadMemberInfo(List<String> curDead) {
        return fundPayFamilyReadDao.selectDeadMemberInfo(curDead);
    }
}
